const isBluetoothAvalibale = require("./bluetooth.util").isBluetoothAvalibale
var httpUrl = require('./constants.js').httpUrl; 
var httpUtil = require('./req.util.js');

class bluetoothManager {
  searchTimer = null; // 查找设备定时器
  lockId = null // 柜锁id
  bluetoothTimeout = 60000; // 蓝牙搜索超时时间
  lockCode = null; // 设备code
  deviceId = null;
  characteristicList = [];
  serviceId = null;
  electricQuantity = null;
  hadReadBattery = false
  timer = null;
  writeResult = null
  onError = null
  onSuccess = null
  errCount = 0

  /**
   * 初始构造方法
   * @param url 请求地址
   */
  constructor(params = {}) {
    this.errCount = 0
    this.resetLock(params)
    // if (params.bluetoothTimeout) this.bluetoothTimeout = params.bluetoothTimeout
    // if (params.lockCode) this.lockCode = params.lockCode
    // if (params.lockId) this.lockId = params.lockId
    // console.log('lockCode ', this.lockCode)
    // this.initBT(null, null, {hideLoading: true})
  }

  initBT = (onSuccess, onError, params = {}) => {
    const that = this
    if (!params.hideLoading) {
      wx.showLoading({
        title: '蓝牙初始化',
      })
    }
    console.log("开始初始化蓝牙模块================================")
    // 监听扫描到新设备事件
    wx.onBluetoothDeviceFound((res) => {
      res.devices.forEach((device) => {
        // 这里可以做一些过滤
        if (device.name && device.name.split(' ').join('') == that.lockCode.trim().split(' ').join('')) {
          console.log('找到对应设备，停止搜索设备=================================', device)
          wx.stopBluetoothDevicesDiscovery()
          clearTimeout(that.searchTimer)
          that.deviceId = device.deviceId
          that.linkDevice(onSuccess, onError, params)
        }
      })
    })

    // 初始化蓝牙模块
    wx.openBluetoothAdapter({
      mode: 'central',
      success: (res) => {
        if (that.deviceId) {
          that.linkDevice(onSuccess, onError, params)
        } else {
          // 开始搜索附近的蓝牙外围设备
          if (!params.hideLoading) {
            wx.showLoading({
              title: '设备搜索中',
            })
          }
          console.log("开始搜索设备================================")
          wx.startBluetoothDevicesDiscovery({
            allowDuplicatesKey: false,
            powerLevel: 'high'
          })
          that.searchTimer = setTimeout(() => {
            console.log("一分钟内未找到设备，停止搜索设备================================")
            wx.stopBluetoothDevicesDiscovery()
            wx.hideLoading()
            wx.showToast({
              icon: 'none',
              title: '未找到设备',
            })
          }, that.bluetoothTimeout)
        }
      },
      fail: (res) => {
        console.log('初始化蓝牙模块失败', res)
        if (res.errCode !== 10001) {
          wx.hideLoading()
          wx.showToast({
            icon: 'none',
            title: res.errMsg,
          })
          that.closeBT()
          return
        }
        console.log("蓝牙功能异常，等待用户更正================================")
        wx.onBluetoothAdapterStateChange((res) => {
          if (!res.available) return
          // 开始搜寻附近的蓝牙外围设备
          console.log("蓝牙功能恢复正常，开始搜索设备================================")
          wx.startBluetoothDevicesDiscovery({
            allowDuplicatesKey: false,
            powerLevel: 'high'
          })
        })
      }
    })
  }

  linkDevice = (onSuccess, onError, params = {}) => {
    if (!params.hideLoading) {
      wx.showLoading({
        title: '开始连接设备',
      })
    }
    console.log('开始连接设备=================================')
    const deviceId = this.deviceId
    console.log(deviceId, this.deviceId)
    wx.createBLEConnection({
      deviceId, // 搜索到设备的 deviceId
      success: (res) => {
        // 连接成功，获取服务
        console.log('连接设备成功=================================', res)
        if (onSuccess) onSuccess(deviceId)
      },
      fail: (err) => {
        if (err.errCode == -1) {
          console.log('设备已连接=================================')
          if (onSuccess) onSuccess(deviceId)
        } else {
          console.log('连接设备失败=================================', err)
          wx.showToast({
            icon: 'none',
            title: '设备连接失败',
          })
          if (onError) onError(err)
        }
      }
    })
  }

  // ArrayBuffer转16进度字符串示例
  buffer2hex(buffer) {
    return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
  }

  /**
   * hex转ArrayBuffer
   */
  stringToBuffer(hex) {
    var typedArray = new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function (h) {
      return parseInt(h, 16)
    }))

    var buffer = typedArray.buffer
    return buffer
  }

  resetLock = (params) => {
    if (params.lockCode) {
      this.lockCode = params.lockCode
    }
    if (params.lockId) {
      this.lockId = params.lockId
    }
    if (params.onSuccess) {
      this.onSuccess = params.onSuccess
    }
    if (params.onError) {
      this.onError = params.onError
    }
    this.deviceId = null
    this.serviceId = null
    this.characteristicList = []
    this.electricQuantity = null
    this.writeResult = null
    if (params.bluetoothTimeout) {
      this.bluetoothTimeout = params.bluetoothTimeout
    } // 蓝牙搜索超时时间
    else {
      this.bluetoothTimeout = 60000
    }
    wx.closeBluetoothAdapter({})
    if(this.onSuccess){
      this.onSuccess(this)
    }
    // this.openLock()
  }

  openLock = (params) => {
    const that = this
    wx.closeBluetoothAdapter({
      success(res) {
        console.log(res)
        that.doOpen()
      }
    })
  }

  doOpen = (callBack) => {
    const that = this
    new Promise((resolve, reject) => {
      // 初始化蓝牙设备
      that.initBT((deviceId) => {
        resolve(deviceId)
      }, error => {
        if (reject) {
          reject(error)
        }
      })
    }).then(deviceId => {
      
      // 获取服务id
      return that.getBLEDeviceServices(deviceId)
    }).then(()=>{
      return new Promise((resolve, reject)=>{
        wx.getBLEDeviceCharacteristics({
          deviceId: that.deviceId, // 搜索到设备的 deviceId
          serviceId: that.serviceId, // 上一步中找到的某个服务
          success: (res) => {
            console.log('查找到的特征值：', res.characteristics)
            that.characteristicList = res.characteristics
            resolve()
          },
          fail: (err) => {
            console.log('获取特征值失败 ', err)
            reject(error)
          }
        })
      })
    }).then(() => {
      // 执行开锁指令
      httpUtil.apphttp(httpUrl.proxyUse, {
        url: httpUrl.cabinetOpen + that.lockCode.split(' ')[0]
      }, {
        method: 'POST',
        loading: false,
      }).then(res2 => {
        if (res2.data) {
          const instr = JSON.parse(res2.data).body
          console.log('开始发送开门指令=============================', instr)
          wx.showLoading({
            title: '开锁中',
          })
          const params = {
            type: 'openLock',
            afterWrite: (result) => {
              clearInterval(openTimer)
              // setTimeout(() => {
              //   that.closeBT()
              // }, 1000)
              wx.hideLoading()
              that.saveOpenLockRecord(callBack)
            }
          }
          const openTimer = setInterval(() => {
            clearInterval(openTimer)
            that.errCount++
            if (that.errCount >= 3) {
              that.writeResult = {}
              wx.hideLoading()
              that.saveOpenLockRecord(callBack)
            } else {
              that.resetLock({})
            }
          }, 10000)
          that.doCharacteristic(that.deviceId, that.serviceId, that.stringToBuffer(instr), params)
        } else {
          wx.showToast({
            icon: 'none',
            title: '未获取到指令信息',
          })
          that.closeBT()
        }
      })
    }).catch(error=>{
      wx.showToast({
        title: error,
      })
      that.closeBT()
    })
  }

  getBattery = () => {
    const that = this
    isBluetoothAvalibale(() => {
      that.initBT((deviceId) => {
        that.getBLEDeviceServices(deviceId).then(res => {
          // that.doOpen()
          httpUtil.apphttp(httpUrl.proxyUse, {
            url: httpUrl.getBattery + that.lockCode.split(' ')[0]
          }, {
            method: 'POST',
            loading: false,
          }).then(res2 => {
            if (res2.data) {
              const instr = JSON.parse(res2.data).body
              console.log('开始发送查询电量指令=============================', instr)
              var data = that.stringToBuffer(instr)
              var hex = that.buffer2hex(data)
              console.log("get battery hex:", hex)
              wx.showLoading({
                title: '开锁中',
              })
              that.doWrite(deviceId, res, instr, {
                type: 'getBattery',
                done: (res) => {
                  httpUtil.apphttp(httpUrl.proxyUse, {
                    url: httpUrl.readBattery + res
                  }, {
                    method: 'POST',
                    loading: false,
                  }).then(res3 => {
                    console.log('电量：', JSON.parse(res3.data).body)
                    that.electricQuantity = JSON.parse(res3.data).body
                    setTimeout(() => {
                      that.doOpen()
                      that.onSuccess ? that.onSuccess() : false
                    }, 2000)
                  })
                }
              })
            } else {
              wx.showToast({
                icon: 'none',
                title: '未获取到指令信息',
              })
              that.closeBT()
            }
          })
        })
      })
    }, () => {
      that.closeBT()
    })
  }

  getBLEDeviceServices = (deviceId) => {
    const that = this
    return new Promise((reslove, rej) => {
      console.log('开始获取设备服务=============================')
      wx.getBLEDeviceServices({
        deviceId, // 搜索到设备的 deviceId
        success: (res) => {
          console.log('查找到的服务列表 ', res)

          console.log('servie found', res.services[1])
          that.serviceId = res.services[1].uuid
          reslove(res.services[1].uuid)

        },
        fail: (err) => {
          console.log('获取设备服务失败=============================')
          rej(err)
        }
      })
    })
  }

  doWrite = (deviceId, serviceId, instr, params = {}) => {
    const that = this
    console.log(instr);
    instr = this.stringToBuffer(instr)
    console.log(instr);
    wx.getBLEDeviceCharacteristics({
      deviceId, // 搜索到设备的 deviceId
      serviceId, // 上一步中找到的某个服务
      success: (res) => {
        console.log('查找到的特征值：', res.characteristics)
        that.characteristicList = res.characteristics
        that.doCharacteristic(deviceId, serviceId, instr, params)
      },
      fail: (err) => {
        console.log('获取特征值失败 ', err)
        that.closeBT()
      }
    })

  }

  doCharacteristic = (deviceId, serviceId, instr, params) => {
    const that = this

    for (let i = 0; i < that.characteristicList.length; i++) {
      let item = that.characteristicList[i]
      if (item.properties.write && item.uuid.indexOf('0000FFF1') != -1) { // 该特征值可写
        console.log('特征值 ', item)
        console.log('开始发送指令=====================================')
        // that.characteristicId = item.uuid
        that.writeBLECharacteristicValue(deviceId, serviceId, item.uuid, instr, params).then(res=>{
          if (params.afterWrite) params.afterWrite()
          else if (params.done) params.done()
          else wx.hideLoading()
        }, error=>{
          if (params.afterWrite) params.afterWrite()
          else if (params.done) params.done()
          else wx.hideLoading()
        })

        // 这里锁具的信道有写版本只能写 不能读，所以只要完成，

        // if (item.properties.write) { // 该特征值可写
        //   // console.log('特征值 ', item)
        //   // console.log('开始发送指令=====================================')
        //   // that.characteristicId = item.uuid
        //   // that.writeBLECharacteristicValue(deviceId, serviceId, item.uuid, instr, params)

        //   // 必须先启用 wx.notifyBLECharacteristicValueChange 才能监听到设备 onBLECharacteristicValueChange 事件
        //   console.log('开始启动notifyBLECharacteristicValueChange============================')
        //   wx.notifyBLECharacteristicValueChange({
        //     deviceId,
        //     serviceId,
        //     characteristicId: item.uuid,
        //     state: true,
        //     success: (res) => {
        //       console.log('notifyBLECharacteristicValueChange启动成功============================== ', res)
        //     },
        //     fail: (err) => {
        //       console.log('notifyBLECharacteristicValueChange启动失败============================== ', err)
        //     }
        //   })
        // }
      }
    }
    var result = ''
    wx.onBLECharacteristicValueChange((characteristic) => {
      // wx.offBLECharacteristicValueChange()
      console.log('characteristic ', characteristic)
      result = result + that.buffer2hex(characteristic.value)
      console.log('特征值变化 ', result)
      if (params.afterWrite) params.afterWrite(result)
      else if (params.done) params.done(result)
      else wx.hideLoading()
    })
  }

  writeBLECharacteristicValue = (deviceId, serviceId, characteristicId, instr, params = {}) => {
    const that = this
    // let pos = 0;
    // let bytes = instr.byteLength;
    // while (bytes > 0) {
    //   let tmpBuffer;
    //   if (bytes > 20) {
    //     tmpBuffer = instr.slice(pos, pos + 20);
    //     pos += 20;
    //     bytes -= 20;
    //     wx.writeBLECharacteristicValue({
    //       deviceId,
    //       serviceId,
    //       characteristicId: characteristicId,
    //       value: tmpBuffer,
    //       success(res) {
    //         console.log('发送成功！', tmpBuffer, res)
    //       }
    //     })
    //     delay(20)
    //   } else {
    //     tmpBuffer = instr.slice(pos, pos + bytes);
    //     pos += bytes;
    //     bytes -= bytes;
    return new Promise((resolve, reject)=>{
      wx.writeBLECharacteristicValue({
        deviceId,
        serviceId,
        characteristicId: characteristicId,
        value: instr,
        success(res) {
          console.log('最后次发送', res)
          that.writeResult = res
          if(resolve){
            resolve(res)
          }
        },
        fail: function (err) {
          console.log('指令发送失败 ', err)
          that.writeResult = err
          if(reject){
            reject(err)
          }
        }
      })
    })
  }

  closeBT = () => {
    // wx.offBLECharacteristicValueChange()
    wx.closeBLEConnection({
      deviceId: this.deviceId,
      success(res) {
        console.log(res)
      },
      fail(err) {
        console.log(err)
      }
    })
    wx.closeBluetoothAdapter({})
    this.hadReadBattery = false
    console.log('操作完成，断开连接和关闭蓝牙适配器=========================')
  }

  /**
   * 上传开锁记录
   * @param {*} res 
   */
  saveOpenLockRecord = (callBack) => {
    wx.showToast({
      icon: this.writeResult.errCode == 0 ? 'success' : 'none',
      title: this.writeResult.errCode == 0 ? '开锁成功' : '开锁失败',
    })
    const that = this
    that.errCount = 0
    if (that.timer) that.timer = null
    that.timer = setTimeout(() => {
      httpUtil.apphttp(httpUrl.saveOpenLockRecord, {
        bedLockId: this.lockId,
        ret: this.writeResult.errCode == 0 ? 1 : 2,
        retContext: this.writeResult.errCode == 0 ? '开锁成功' : '开锁失败',
        electricQuantity: this.electricQuantity
      }, {
        method: 'POST',
        loading: false,
      }).then(res => {
        if (callBack) callBack()
        // if(that.onSuccess) that.onSuccess()
      }).catch(err => {
        if (callBack) callBack()
        // if(that.onError) that.onError()
      })
    }, 2000)
  }
}

function delay(milSec) {

  return new Promise(resolve => {

    setTimeout(resolve, milSec)

  })

}

module.exports = {
  bluetoothManager
}